package nancal.mp.mvc.dev


import io.swagger.annotations.Api
import io.swagger.annotations.ApiOperation
import nancal.mp.db.mongo.entity.*
import nancal.mp.db.mongo.entity.yapi.api
import nancal.mp.db.mongo.mor
import nbcp.base.annotation.*
import nbcp.base.annotation.mvc.*
import nbcp.base.comm.*
import nbcp.base.db.IdName
import nbcp.base.extend.*
import nbcp.base.json.*
import nbcp.base.utils.RecursionUtil
import nbcp.myoql.db.mongo.query
import nbcp.myoql.db.mongo.queryById
import nbcp.myoql.db.mongo.update

import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import javax.servlet.http.HttpServletRequest

/**
 * Created by CodeGenerator at 2021-04-12 12:10:50
 */
@Api(description = "Git服务器", tags = arrayOf("GitServer"))
@RestController
@RequestMapping("/dev/yapi")
class YapiController {

    open class YapiInterface : api() {
        var emptyColumnCount: Int = 0
        var leafEmptyColumnCount: Int = 0
    }


    @ApiOperation("列表")
    @PostMapping("/list")
    fun list(
        id: Int, //当列表列新一条后，刷新时使用
        project: Int,
        name: String,
        leafEmptyColumnCount: Int,
        @org.springframework.web.bind.annotation.RequestBody query: PagerModel<Any?>,
        request: HttpServletRequest
    ): ListResult<YapiInterface> {

        if (leafEmptyColumnCount == 0) {
            var result = mor.yapi.api.query()
                .apply {
                    if (id.HasValue) {
                        this.where { it.id mongoEquals id }
                    } else {
                        if (project.HasValue) {
                            this.where { it.project_id mongoEquals project }
                        }

                        if (name.trim().HasValue) {
                            this.linkOr({ it.title mongoLike name.trim() },
                                { it.path mongoLike name.trim() })
                        }
                    }
                }
                .orderByAsc { it.catid }
                .withPager(query)
                .toListResult(YapiInterface::class.java);


            var catIds = result.data.map { it.catid }.toSet();

            var cats = mor.yapi.api_cat.query()
                .where { it.id mongoIn catIds }
                .select { it.id }
                .select { it.name }
                .toList(IdName::class.java)

            result.data.forEach { api ->
                api.catName = cats.firstOrNull { it.id.AsInt() == api.catid }?.name ?: "";
            }

            result.data.forEach {
                var p1 = getEmptyPsCount(it.req_body_other);
                var p2 = getEmptyPsCount(it.res_body);

                it.emptyColumnCount = p1.first + p2.first;
                it.leafEmptyColumnCount = p1.second + p2.second;
            }

            return result;
        }


        var list = mor.yapi.api.query()
            .apply {
                if (id.HasValue) {
                    this.where { it.id mongoEquals id }
                }

                this.where { it.project_id mongoEquals project }

                if (name.trim().HasValue) {
                    this.where { it.title mongoLike name.trim() }
                }
            }
            .orderByAsc { it.catid }
            .toList(YapiInterface::class.java);

        list.forEach {
            var p1 = getEmptyPsCount(it.req_body_other);
            var p2 = getEmptyPsCount(it.res_body);

            it.emptyColumnCount = p1.first + p2.first;
            it.leafEmptyColumnCount = p1.second + p2.second;
        }

        list = list.filter { it.emptyColumnCount > leafEmptyColumnCount }
            .Slice(query.skip, query.skip + query.take)
            .toMutableList();


        var cats = mor.yapi.api_cat.query()
            .where { it.id mongoIn list.map { it.catid } }
            .select { it.id }
            .select { it.name }
            .toList(IdName::class.java)

        list.forEach { api ->
            api.catName = cats.firstOrNull { it.id.AsInt() == api.catid }?.name ?: "";
        }

        return ListResult.of(list, list.size.toLong());
    }

    private fun getEmptyPsCount(jsonString: String?): Pair<Int, Int> {
        if (jsonString.isNullOrEmpty()) return 0 to 0;
        var json: JsonMap = JsonMap();
        try {
            json = jsonString.FromJson<JsonMap>()!!
        } catch (e: Exception) {
            return 0 to 0;
        }
        var emptyCount = 0;
        var leafEmptyColumnCount = 0;
        var type = json.get("type");
        if (type == "object" || type == "array") {
            if (json.containsKey("properties")) {
                var ps = json.get("properties")!!;
                RecursionUtil.recursionAny(ps, { mapItem ->
                    var type = mapItem.get("type");
                    if (type == null) {
                        return@recursionAny true;
                    }

                    //有的时， 内容会嵌套在 type 的value 里。
                    if (type.javaClass.IsStringType == false) {
                        return@recursionAny true
                    }
                    var remark = mapItem.get("description").AsString()
                    var title = mapItem.get("title").AsString()
                    if (remark.isNullOrEmpty() && title.isNullOrEmpty()) {

                        if (type == "object" || type == "array") {

                        } else {
                            leafEmptyColumnCount++;
                        }

                        emptyCount++;
                    }
                    return@recursionAny true
                }, { l ->
                    true
                }, { o ->
                    true
                });
            }
        }

        return emptyCount to leafEmptyColumnCount;
    }

    class CategoryInfo(var group: IdName, var project: IdName, var category: IdName)

    @ApiOperation("列表")
    @PostMapping("/category-info")
    fun categoryInfo(categoryId: Int): ApiResult<CategoryInfo> {
        var cat = mor.yapi.api_cat.query()
            .where { it.id mongoEquals categoryId }
            .toEntity()
            .must().elseThrow { "找不到分类" }

        var project = mor.yapi.project.query()
            .where { it.id mongoEquals cat.project_id }
            .toEntity()
            .must().elseThrow { "找不到项目" }

        var group = mor.yapi.group.query()
            .where { it.id mongoEquals project.group_id }
            .toEntity()
            .must().elseThrow { "找不到项目" }


        return ApiResult.of(
            YapiController.CategoryInfo(
                IdName(group.id.toString(), group.group_name),
                IdName(project.id.toString(), project.name),
                IdName(cat.id.toString(), cat.name),
            )
        )
    }

    @ApiOperation("列表")
    @PostMapping("/groups")
    fun groups(): ListResult<IdName> {
        return mor.yapi.group.query()
            .where { it.type mongoEquals "public" }
            .toList()
            .map { IdName(it.id.toString(), it.group_name) }
            .let {
                return ListResult.of(it);
            }
    }

    @ApiOperation("列表")
    @PostMapping("/projects")
    fun projects(groupId: Int): ListResult<IdName> {
        return mor.yapi.project.query()
            .where { it.group_id mongoEquals groupId }
            .toList()
            .map { IdName(it.id.toString(), it.name) }
            .let {
                return ListResult.of(it);
            }
    }

    @ApiOperation("列表")
    @PostMapping("/categories")
    fun categories(projectId: Int): ListResult<IdName> {
        return mor.yapi.api_cat.query()
            .where { it.project_id mongoEquals projectId }
            .toList()
            .map { IdName(it.id.toString(), it.name) }
            .let {
                return ListResult.of(it);
            }
    }

    @PostMapping("/move")
    fun move(sourceCategoryId: Int, targetCategoryId: Int): JsonResult {
        var sourceCategoryEntity = mor.yapi.api_cat.query()
            .where { it.id mongoEquals sourceCategoryId }
            .toEntity()
            .must().elseThrow { "找不到分类" }

        var sourceProject = mor.yapi.project.query()
            .where { it.id mongoEquals sourceCategoryEntity.project_id }
            .toEntity()
            .must().elseThrow { "找不到项目" }


        var targetCategoryEntity = mor.yapi.api_cat.query()
            .where { it.id mongoEquals targetCategoryId }
            .toEntity()
            .must().elseThrow { "找不到分类" }

        var targetProject = mor.yapi.project.query()
            .where { it.id mongoEquals targetCategoryEntity.project_id }
            .toEntity()
            .must().elseThrow { "找不到项目" }

        return mor.yapi.api.update()
            .where { it.catid mongoEquals sourceCategoryId }
            .where { it.project_id mongoEquals sourceProject.id }
            .set { it.catid to targetCategoryId }
            .set { it.project_id to targetProject.id }
            .exec()
            .let {
                return JsonResult();
            }
    }


    @PostMapping("/set-open")
    fun setOpen(): JsonResult {
        mor.yapi.project.update()
            .set { it.project_type to "public" }
            .where { it.project_type mongoNotEquals "public" }
            .exec();

        return JsonResult()
    }

    @PostMapping
    fun markdown(@PathVariable("id") id: String): ApiResult<String> {
        var api = mor.yapi.api.queryById(id).toEntity().throwIfNull { "找不到yapi" };

        return ApiResult();
    }
}